/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.paboo.chart.datamatrix;

import com.google.zxing.Dimension;
import com.google.zxing.datamatrix.encoder.*;
import com.google.zxing.qrcode.encoder.ByteMatrix;

/**
 * @author Leonard
 */
public class ZxingUtil {

    // Content is must be ISO 8859-1
    public static ByteMatrix encode(String contents) {
        SymbolShapeHint shape = SymbolShapeHint.FORCE_SQUARE;
        Dimension minSize = null;
        Dimension maxSize = null;

        // 1. step: Data encodation
        String encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize);

        SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.length(), shape, minSize, maxSize, true);

        // 2. step: ECC generation
        String codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo);

        // 3. step: Module placement in Matrix
        DefaultPlacement placement = new DefaultPlacement(codewords, symbolInfo.getSymbolDataWidth(),
                symbolInfo.getSymbolDataHeight());
        placement.place();

        // 4. step: low-level encoding
        return encodeLowLevel(placement, symbolInfo);
    }

    private static ByteMatrix encodeLowLevel(DefaultPlacement placement, SymbolInfo symbolInfo) {
        int symbolWidth = symbolInfo.getSymbolDataWidth();
        int symbolHeight = symbolInfo.getSymbolDataHeight();

        ByteMatrix matrix = new ByteMatrix(symbolInfo.getSymbolWidth(), symbolInfo.getSymbolHeight());

        int matrixY = 0;

        for (int y = 0; y < symbolHeight; y++) {
            // Fill the top edge with alternate 0 / 1
            int matrixX;
            if ((y % symbolInfo.matrixHeight) == 0) {
                matrixX = 0;
                for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
                    matrix.set(matrixX, matrixY, (x % 2) == 0);
                    matrixX++;
                }
                matrixY++;
            }
            matrixX = 0;
            for (int x = 0; x < symbolWidth; x++) {
                // Fill the right edge with full 1
                if ((x % symbolInfo.matrixWidth) == 0) {
                    matrix.set(matrixX, matrixY, true);
                    matrixX++;
                }
                matrix.set(matrixX, matrixY, placement.getBit(x, y));
                matrixX++;
                // Fill the right edge with alternate 0 / 1
                if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1) {
                    matrix.set(matrixX, matrixY, (y % 2) == 0);
                    matrixX++;
                }
            }
            matrixY++;
            // Fill the bottom edge with full 1
            if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1) {
                matrixX = 0;
                for (int x = 0; x < symbolInfo.getSymbolWidth(); x++) {
                    matrix.set(matrixX, matrixY, true);
                    matrixX++;
                }
                matrixY++;
            }
        }

        return matrix;
    }

}
